"""
告警分级处理系统
实现告警分级、自动升级机制、处理工作流
"""
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Any
from django.utils import timezone
from django.db import transaction
from django.contrib.auth.models import User

from ..models import MonitoringAlert, AlertRule, NotificationChannel
from .notification_service import NotificationService

logger = logging.getLogger(__name__)


class AlertProcessor:
    """告警处理器"""

    def __init__(self):
        self.notification_service = NotificationService()

        # 告警级别优先级映射（数字越大优先级越高）
        self.severity_priority = {
            'not_classified': 0,
            'information': 1,
            'warning': 2,
            'average': 3,
            'high': 4,
            'disaster': 5
        }

        # 自动升级时间配置（分钟）
        self.escalation_times = {
            'information': 60,      # 信息级别60分钟后升级
            'warning': 30,          # 警告级别30分钟后升级
            'average': 20,          # 一般严重20分钟后升级
            'high': 10,             # 严重级别10分钟后升级
            'disaster': 5           # 灾难级别5分钟后升级
        }

    def process_new_alert(self, alert: MonitoringAlert) -> Dict[str, Any]:
        """处理新告警"""
        try:
            with transaction.atomic():
                # 1. 告警分级处理
                self._apply_severity_rules(alert)

                # 2. 检查是否需要抑制
                if self._should_suppress_alert(alert):
                    alert.status = 'suppressed'
                    alert.save()
                    return {
                        'success': True,
                        'action': 'suppressed',
                        'message': '告警已被抑制'
                    }

                # 3. 应用告警规则
                applied_rules = self._apply_alert_rules(alert)

                # 4. 发送通知
                if alert.status == 'active':
                    self.notification_service.send_alert_notifications([alert])

                return {
                    'success': True,
                    'action': 'processed',
                    'applied_rules': applied_rules,
                    'severity': alert.severity,
                    'status': alert.status
                }

        except Exception as e:
            logger.error(f"处理告警失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def _apply_severity_rules(self, alert: MonitoringAlert):
        """应用严重程度规则"""
        # 基于告警内容调整严重程度
        title_lower = alert.title.lower()
        description_lower = alert.description.lower()

        # 关键词匹配升级规则
        critical_keywords = ['down', 'offline', 'unreachable', '宕机', '离线', '不可达']
        high_keywords = ['high', 'critical', 'error', '错误', '严重', '高']
        medium_keywords = ['warning', 'warn', '警告', '告警']

        current_priority = self.severity_priority.get(alert.severity, 0)

        # 检查关键词并升级
        if any(keyword in title_lower or keyword in description_lower for keyword in critical_keywords):
            if current_priority < self.severity_priority['disaster']:
                alert.severity = 'disaster'
                logger.info(f"告警 {alert.id} 因关键词匹配升级为灾难级别")
        elif any(keyword in title_lower or keyword in description_lower for keyword in high_keywords):
            if current_priority < self.severity_priority['high']:
                alert.severity = 'high'
                logger.info(f"告警 {alert.id} 因关键词匹配升级为严重级别")
        elif any(keyword in title_lower or keyword in description_lower for keyword in medium_keywords):
            if current_priority < self.severity_priority['average']:
                alert.severity = 'average'
                logger.info(f"告警 {alert.id} 因关键词匹配升级为一般严重级别")

    def _should_suppress_alert(self, alert: MonitoringAlert) -> bool:
        """判断是否应该抑制告警"""
        # 检查是否有相同主机的高优先级告警
        higher_priority_alerts = MonitoringAlert.objects.filter(
            host=alert.host,
            status='active',
            severity__in=[
                severity for severity, priority in self.severity_priority.items()
                if priority > self.severity_priority.get(alert.severity, 0)
            ]
        ).exists()

        if higher_priority_alerts:
            logger.info(f"告警 {alert.id} 因存在更高优先级告警而被抑制")
            return True

        # 检查重复告警（5分钟内相同标题的告警）
        recent_time = timezone.now() - timedelta(minutes=5)
        duplicate_alerts = MonitoringAlert.objects.filter(
            host=alert.host,
            title=alert.title,
            status__in=['active', 'acknowledged'],
            created_at__gte=recent_time
        ).exclude(id=alert.id).exists()

        if duplicate_alerts:
            logger.info(f"告警 {alert.id} 因重复而被抑制")
            return True

        return False

    def _apply_alert_rules(self, alert: MonitoringAlert) -> List[Dict]:
        """应用告警规则"""
        applied_rules = []

        # 获取匹配的告警规则
        matching_rules = AlertRule.objects.filter(
            is_active=True,
            zabbix_server=alert.zabbix_server
        )

        for rule in matching_rules:
            try:
                # 检查规则条件
                if self._check_rule_condition(alert, rule):
                    # 应用规则动作 - 主要是发送通知
                    if rule.enable_notification:
                        self._send_rule_notification(alert, rule)

                    applied_rules.append({
                        'rule_id': rule.id,
                        'rule_name': rule.name,
                        'metric_name': rule.metric_name,
                        'condition': rule.condition,
                        'threshold_value': rule.threshold_value
                    })
            except Exception as e:
                logger.error(f"应用告警规则 {rule.id} 失败: {e}")

        return applied_rules

    def _map_severity_to_rule_level(self, severity: str) -> str:
        """映射告警级别到规则级别"""
        mapping = {
            'disaster': 'critical',
            'high': 'high',
            'average': 'medium',
            'warning': 'low',
            'information': 'low',
            'not_classified': 'low'
        }
        return mapping.get(severity, 'low')

    def _check_rule_condition(self, alert: MonitoringAlert, rule: AlertRule) -> bool:
        """检查规则条件"""
        try:
            # 1. 检查主机组匹配（如果规则配置了主机组）
            if rule.host_groups.exists() and alert.host:
                host_groups = alert.host.groups.all()
                rule_groups = rule.host_groups.all()
                if not any(group in rule_groups for group in host_groups):
                    logger.debug(f"告警 {alert.id} 主机组不匹配规则 {rule.id}")
                    return False

            # 2. 检查告警标题或描述中是否包含监控项名称
            metric_name = rule.metric_name.lower() if rule.metric_name else ""
            alert_title = alert.title.lower()
            alert_desc = alert.description.lower()

            # 如果监控项名称为空或为通配符，则匹配所有告警
            if not metric_name or metric_name in ['*', 'all', '全部']:
                logger.debug(f"告警 {alert.id} 匹配通用规则 {rule.id} (通配符)")
                return True

            # 简单的关键词匹配
            if metric_name in alert_title or metric_name in alert_desc:
                logger.debug(f"告警 {alert.id} 匹配规则 {rule.id} (关键词匹配)")
                return True

            # 3. 检查原始数据中的监控项信息
            if alert.raw_data:
                raw_data_str = str(alert.raw_data).lower()
                if metric_name in raw_data_str:
                    logger.debug(f"告警 {alert.id} 匹配规则 {rule.id} (原始数据匹配)")
                    return True

            # 4. 基于告警级别的匹配（如果没有配置监控项名称）
            if not metric_name:
                severity_mapping = {
                    'disaster': 'critical',
                    'high': 'high',
                    'average': 'medium',
                    'warning': 'low',
                    'information': 'low',
                    'not_classified': 'low'
                }

                mapped_severity = severity_mapping.get(alert.severity, 'low')
                if mapped_severity == rule.severity:
                    logger.debug(f"告警 {alert.id} 匹配规则 {rule.id} (严重程度匹配)")
                    return True

            logger.debug(f"告警 {alert.id} 不匹配规则 {rule.id}")
            return False

        except Exception as e:
            logger.error(f"检查规则条件失败: {e}")
            return False

    def _apply_rule_action(self, alert: MonitoringAlert, rule: AlertRule):
        """应用规则动作"""
        if rule.action == 'escalate':
            # 升级告警
            self._escalate_alert(alert)
        elif rule.action == 'suppress':
            # 抑制告警
            alert.status = 'suppressed'
            alert.save()
        elif rule.action == 'notify':
            # 发送特定通知
            self._send_rule_notification(alert, rule)

    def _escalate_alert(self, alert: MonitoringAlert):
        """升级告警"""
        current_priority = self.severity_priority.get(alert.severity, 0)

        # 找到下一个级别
        next_severity = None
        for severity, priority in self.severity_priority.items():
            if priority == current_priority + 1:
                next_severity = severity
                break

        if next_severity:
            alert.severity = next_severity
            alert.save()
            logger.info(f"告警 {alert.id} 已升级到 {next_severity}")

    def _send_rule_notification(self, alert: MonitoringAlert, rule: AlertRule):
        """发送规则通知"""
        try:
            # 获取规则配置的通知渠道
            rule_channels = rule.notification_channels.filter(is_active=True)

            if rule_channels.exists():
                # 使用规则指定的通知渠道
                for channel in rule_channels:
                    self.notification_service._send_single_notification(alert, channel)
                logger.info(f"告警规则 {rule.name} 触发，已发送通知到 {rule_channels.count()} 个渠道")
            else:
                # 如果规则没有指定通知渠道，使用默认的通知服务
                self.notification_service.send_alert_notifications([alert])
                logger.info(f"告警规则 {rule.name} 触发，已发送默认通知")

        except Exception as e:
            logger.error(f"发送规则通知失败: {e}")

    def process_alert_escalation(self):
        """处理告警自动升级"""
        try:
            # 获取需要升级的告警
            for severity, escalation_time in self.escalation_times.items():
                cutoff_time = timezone.now() - timedelta(minutes=escalation_time)

                alerts_to_escalate = MonitoringAlert.objects.filter(
                    severity=severity,
                    status='active',
                    event_time__lte=cutoff_time,
                    acknowledged_time__isnull=True  # 未确认的告警才升级
                )

                for alert in alerts_to_escalate:
                    try:
                        self._escalate_alert(alert)
                        # 发送升级通知
                        self.notification_service.send_alert_notifications([alert])
                    except Exception as e:
                        logger.error(f"升级告警 {alert.id} 失败: {e}")

        except Exception as e:
            logger.error(f"处理告警升级失败: {e}")

    def get_alert_workflow_status(self, alert: MonitoringAlert) -> Dict[str, Any]:
        """获取告警工作流状态"""
        workflow_steps = []

        # 创建步骤
        workflow_steps.append({
            'step': 'created',
            'status': 'completed',
            'timestamp': alert.created_at.isoformat(),
            'description': '告警已创建'
        })

        # 确认步骤
        if alert.acknowledged_time:
            workflow_steps.append({
                'step': 'acknowledged',
                'status': 'completed',
                'timestamp': alert.acknowledged_time.isoformat(),
                'user': alert.acknowledged_by.username if alert.acknowledged_by else None,
                'description': '告警已确认'
            })
        elif alert.status == 'active':
            workflow_steps.append({
                'step': 'acknowledged',
                'status': 'pending',
                'description': '等待确认'
            })

        # 解决步骤
        if alert.resolved_time:
            workflow_steps.append({
                'step': 'resolved',
                'status': 'completed',
                'timestamp': alert.resolved_time.isoformat(),
                'description': '告警已解决'
            })
        elif alert.status in ['active', 'acknowledged']:
            workflow_steps.append({
                'step': 'resolved',
                'status': 'pending',
                'description': '等待解决'
            })

        return {
            'alert_id': alert.id,
            'current_status': alert.status,
            'severity': alert.severity,
            'workflow_steps': workflow_steps,
            'can_acknowledge': alert.status == 'active',
            'can_resolve': alert.status in ['active', 'acknowledged']
        }


# 全局告警处理器实例
alert_processor = AlertProcessor()
